#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <errno.h>
#include <arpa/inet.h>

#define MAX_EVENTS 64
#define SERVER_PORT 8080
#define WORKER_THREADS 4
#define BUFFER_SIZE 1024
#define MAX_CLIENTS_PER_ROOM 100
#define MAX_CLIENTS 1000
#define MAX_USERS 1000

// 消息类型定义
#define MSG_PUBLIC 1      // 公共消息
#define MSG_PRIVATE 2     // 私聊消息
#define MSG_SYSTEM 3      // 系统消息
#define MSG_JOIN 4        // 加入聊天室
#define MSG_LEAVE 5       // 离开聊天室
#define MSG_RENAME 6      // 改名
#define MSG_LOGIN 7       // 登录请求
#define MSG_REGISTER 8    // 注册请求
#define MSG_AUTH_RESULT 9 // 认证结果

// 客户端命令格式：
// 公共消息: /msg <content>
// 私聊消息: /private <target> <content>
// 改名: /nick <new_name>
// 列出用户: /list
// 退出: /quit
// 登录: /login <username> <password>
// 注册: /register <username> <password>

// 全局 epoll 实例 (主Reactor)
int main_epoll_fd;

typedef struct chat_message chat_message;
typedef struct chat_room chat_room;
typedef struct client_info client_info;
typedef struct user_info user_info;

// 用户信息结构
struct user_info
{
    char username[32];
    char password[32];
    int is_online;
};

// 线程参数结构
typedef struct
{
    int epoll_fd;
    int thread_id;
} worker_args;

struct chat_room
{
    char name[32];                              // 聊天室名称
    client_info *members[MAX_CLIENTS_PER_ROOM]; // 成员列表
    int member_count;                           // 当前成员数
};

struct client_info
{
    int fd;                   // 客户端文件描述符
    char name[32];            // 用户名
    char ip[INET_ADDRSTRLEN]; // IP地址
    int port;                 // 端口
    chat_room *room;          // 所在聊天室
    int is_authenticated;     // 是否已认证
};

struct chat_message
{
    int type;           // 消息类型
    char sender[32];    // 发送者
    char content[1024]; // 消息内容
    char target[32];    // 目标（私聊时使用）
    char password[32];  // 密码（登录注册时使用）
};

// 默认聊天房间
chat_room *default_room;
// 全局客户端管理
client_info *clients[MAX_CLIENTS];
int total_clients = 0;
// 用户数据库
user_info users[MAX_USERS];
int total_users = 0;

// 函数声明
void broadcast_message(chat_room *room, chat_message *msg, int exclude_fd);
void handle_message(client_info *client, char *buffer);
void handle_data(int fd);
client_info *add_client(int fd, struct sockaddr_in *addr);
void remove_client(client_info *client);
client_info *get_client_by_fd(int fd);
user_info *find_user(const char *username);
int register_user(const char *username, const char *password);
int authenticate_user(const char *username, const char *password);

// 广播消息函数
void broadcast_message(chat_room *room, chat_message *msg, int exclude_fd)
{
    for (int i = 0; i < room->member_count; i++)
    {
        client_info *client = room->members[i];
        if (client->fd != exclude_fd && client->is_authenticated)
        {
            write(client->fd, msg, sizeof(chat_message));
        }
    }
}

// 查找用户
user_info *find_user(const char *username)
{
    for (int i = 0; i < total_users; i++)
    {
        if (strcmp(users[i].username, username) == 0)
        {
            return &users[i];
        }
    }
    return NULL;
}

// 注册用户
int register_user(const char *username, const char *password)
{
    if (total_users >= MAX_USERS)
    {
        return 0; // 用户已满
    }

    if (find_user(username) != NULL)
    {
        return -1; // 用户已存在
    }

    // 先保存到当前索引，然后再增加计数器
    strncpy(users[total_users].username, username, sizeof(users[total_users].username) - 1);
    strncpy(users[total_users].password, password, sizeof(users[total_users].password) - 1);
    users[total_users].username[sizeof(users[total_users].username) - 1] = '\0';  // 确保以 null 结尾
    users[total_users].password[sizeof(users[total_users].password) - 1] = '\0';  // 确保以 null 结尾
    users[total_users].is_online = 0;
    
    total_users++;  // 最后再增加计数器

    return 1; // 注册成功
}

// 用户认证
int authenticate_user(const char *username, const char *password)
{
    user_info *user = find_user(username);
    if (user == NULL)
    {
        return 0; // 用户不存在
    }

    if (strcmp(user->password, password) != 0)
    {
        return -1; // 密码错误
    }
    user->is_online = 1;
    return 1; // 认证成功
}

void handle_message(client_info *client, char *buffer)
{
    if (client == NULL || buffer == NULL)
    {
        printf("处理消息错误\n");
        return;
    }

    chat_message msg;
    memcpy(&msg, buffer, sizeof(chat_message));

    msg.content[sizeof(msg.content) - 1] = '\0';
    msg.sender[sizeof(msg.sender) - 1] = '\0';
    msg.target[sizeof(msg.target) - 1] = '\0';
    msg.password[sizeof(msg.password) - 1] = '\0';
    printf("收到来自 %s 的消息: %s\n", msg.sender, msg.content);
    printf("收到消息类型: %d\n", msg.type);
    printf("MSG_LOGIN = %d, MSG_REGISTER = %d\n", MSG_LOGIN, MSG_REGISTER);

    // 未认证用户只能进行登录和注册操作
    if (!client->is_authenticated)
    {
        chat_message response;
        memset(&response, 0, sizeof(response));
        response.type = MSG_AUTH_RESULT;
        if (msg.type == MSG_LOGIN)
        {
            printf("登录请求\n");
            int auth_result = authenticate_user(msg.sender, msg.password);
            if (auth_result == 1)
            {
                strcpy(response.content, "Login successful!");
                client->is_authenticated = 1;
                strcpy(client->name, msg.sender);
                strcpy(response.target, msg.sender);
                // 加入聊天室
                client->room = default_room;
                default_room->members[default_room->member_count++] = client;

                // 广播加入消息
                chat_message join_msg = {
                    .type = MSG_JOIN,
                    .sender = "",
                    .content = ""};
                strcpy(join_msg.sender, client->name);
                broadcast_message(client->room, &join_msg, -1);
            }
            else if (auth_result == 0)
            {
                strcpy(response.content, "用户不存在！");
            }
            else
            {
                strcpy(response.content, "密码错误！");
            }
        }
        else if (msg.type == MSG_REGISTER)
        {
            int reg_result = register_user(msg.sender, msg.password);
            if (reg_result == 1)
            {
                strcpy(response.content, "注册成功！请登录。");
            }
            else if (reg_result == 0)
            {
                strcpy(response.content, "用户数量已达上限！");
            }
            else
            {
                strcpy(response.content, "用户名已存在！");
            }
        }
        else
        {
            strcpy(response.content, "请先登录或注册！");
        }

        write(client->fd, &response, sizeof(chat_message));
        printf("响应: %s\n", response.content);
        return;
    }

    switch (msg.type)
    {
    case MSG_PUBLIC:
        broadcast_message(client->room, &msg, client->fd);
        break;

    case MSG_PRIVATE:
        for (int i = 0; i < client->room->member_count; i++)
        {
            if (strcmp(client->room->members[i]->name, msg.target) == 0)
            {
                write(client->room->members[i]->fd, &msg, sizeof(chat_message));
                break;
            }
        }
        break;

    case MSG_JOIN:
        sprintf(msg.content, "%s 加入了聊天室\n", client->name);
        msg.type = MSG_SYSTEM;
        broadcast_message(client->room, &msg, -1);
        break;

    case MSG_LEAVE:
        sprintf(msg.content, "%s 离开了聊天室\n", client->name);
        msg.type = MSG_SYSTEM;
        broadcast_message(client->room, &msg, -1);
        break;
    case MSG_LOGIN:
        memset(&msg, 0, sizeof(msg));
        msg.type = MSG_SYSTEM;
        strcpy(msg.content, "您已经登录了！");
        write(client->fd, &msg, sizeof(chat_message));
    }
}

// 设置非阻塞
void set_nonblocking(int fd)
{
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

void handle_data(int fd)
{
    client_info *client = get_client_by_fd(fd);
    char buffer[sizeof(chat_message)];
    ssize_t bytes_read;

    while (1)
    {
        bytes_read = read(fd, buffer, sizeof(buffer));
        if (bytes_read < 0)
        {
            if (errno == EAGAIN || errno == EWOULDBLOCK)
            {
                break;
            }
            perror("读取错误");
            remove_client(client);
            return;
        }
        else if (bytes_read == 0)
        {
            printf("客户端 %s 断开连接\n", client->name);
            remove_client(client);
            return;
        }

        handle_message(client, buffer);
    }
}

client_info *add_client(int fd, struct sockaddr_in *addr)
{
    client_info *client = malloc(sizeof(client_info));
    client->fd = fd;
    client->is_authenticated = 0;
    inet_ntop(AF_INET, &addr->sin_addr, client->ip, INET_ADDRSTRLEN);
    client->port = ntohs(addr->sin_port);
    strcpy(client->name, "游客");
    client->room = NULL;

    // 将客户端添加到全局客户端管理数组
    for (int i = 0; i < MAX_CLIENTS; i++)
    {
        if (clients[i] == NULL)
        {
            clients[i] = client;
            break;
        }
    }
    return client;
}

void remove_client(client_info *client)
{
    if (client->is_authenticated && client->room)
    {
        // 从聊天室移除
        for (int i = 0; i < client->room->member_count; i++)
        {
            if (client->room->members[i] == client)
            {
                client->room->members[i] = client->room->members[client->room->member_count - 1];
                client->room->member_count--;
                break;
            }
        }

        // 广播离开消息
        chat_message leave_msg = {
            .type = MSG_LEAVE,
            .sender = "",
            .content = ""};
        strcpy(leave_msg.sender, client->name);
        broadcast_message(client->room, &leave_msg, -1);
    }

    // 从全局客户端数组移除
    for (int i = 0; i < MAX_CLIENTS; i++)
    {
        if (clients[i] == client)
        {
            clients[i] = NULL;
            total_clients--;
            break;
        }
    }

    close(client->fd);
    free(client);
}

// 工作线程函数
void *worker_thread(void *arg)
{
    worker_args *args = (worker_args *)arg;
    struct epoll_event events[MAX_EVENTS];

    while (1)
    {
        int n = epoll_wait(args->epoll_fd, events, MAX_EVENTS, -1);
        for (int i = 0; i < n; i++)
        {
            if (events[i].events & EPOLLIN)
            {
                handle_data(events[i].data.fd);
            }
        }
    }

    return NULL;
}

client_info *get_client_by_fd(int fd)
{
    for (int i = 0; i < MAX_CLIENTS; i++)
    {
        if (clients[i] && clients[i]->fd == fd)
        {
            return clients[i];
        }
    }
    return NULL;
}

int main()
{
    struct epoll_event event;
    struct sockaddr_in addr;
    int server_fd, client_fd;

    // 初始化默认聊天室
    default_room = (chat_room *)malloc(sizeof(chat_room));
    default_room->member_count = 0;
    strcpy(default_room->name, "聊天室1");
    memset(default_room->members, 0, sizeof(default_room->members));

    // 初始化用户数据库
    memset(users, 0, sizeof(users));
    total_users = 0;

    // 创建 TCP socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
        perror("创建套接字失败");
        exit(EXIT_FAILURE);
    }

    // 设置 SO_REUSEADDR
    int opt = 1;
    setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    // 绑定端口
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(SERVER_PORT);

    if (bind(server_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        perror("绑定失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 开始监听
    if (listen(server_fd, SOMAXCONN) < 0)
    {
        perror("监听失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    printf("服务器正在监听端口 %d\n", SERVER_PORT);

    // 创建主 epoll 实例
    if ((main_epoll_fd = epoll_create1(0)) < 0)
    {
        perror("创建epoll实例失败");
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    // 添加服务器 socket 到主 epoll
    event.events = EPOLLIN;
    event.data.fd = server_fd;
    if (epoll_ctl(main_epoll_fd, EPOLL_CTL_ADD, server_fd, &event) < 0)
    {
        perror("epoll控制失败");
        close(server_fd);
        close(main_epoll_fd);
        exit(EXIT_FAILURE);
    }

    // 创建工作线程
    pthread_t threads[WORKER_THREADS];
    worker_args thread_args[WORKER_THREADS];
    int worker_epoll_fd[WORKER_THREADS];

    for (int i = 0; i < WORKER_THREADS; i++)
    {
        if ((worker_epoll_fd[i] = epoll_create1(0)) < 0)
        {
            perror("工作线程epoll创建失败");
            exit(EXIT_FAILURE);
        }

        thread_args[i].epoll_fd = worker_epoll_fd[i];
        thread_args[i].thread_id = i;

        if (pthread_create(&threads[i], NULL, worker_thread, &thread_args[i]) != 0)
        {
            perror("创建工作线程失败");
            exit(EXIT_FAILURE);
        }
        printf("工作线程 %d 已创建\n", i);
    }

    // 主事件循环
    struct epoll_event events[MAX_EVENTS];
    int current_worker = 0;

    while (1)
    {
        int n = epoll_wait(main_epoll_fd, events, MAX_EVENTS, -1);

        for (int i = 0; i < n; i++)
        {
            if (events[i].data.fd == server_fd)
            {
                struct sockaddr_in client_addr;
                socklen_t client_len = sizeof(client_addr);

                if ((client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len)) < 0)
                {
                    perror("接受连接失败");
                    continue;
                }

                set_nonblocking(client_fd);
                client_info *client = add_client(client_fd, &client_addr);

                // 发送欢迎消息
                chat_message welcome_msg = {
                    .type = MSG_SYSTEM,
                    .content = "欢迎！请先登录或注册。"};
                write(client_fd, &welcome_msg, sizeof(welcome_msg));

                // 添加到工作线程的epoll
                event.events = EPOLLIN | EPOLLET;
                event.data.fd = client_fd;
                epoll_ctl(worker_epoll_fd[current_worker], EPOLL_CTL_ADD, client_fd, &event);

                current_worker = (current_worker + 1) % WORKER_THREADS;
            }
        }
    }

    // 清理
    close(server_fd);
    close(main_epoll_fd);
    for (int i = 0; i < WORKER_THREADS; i++)
    {
        close(worker_epoll_fd[i]);
    }

    return 0;
}
